package org.cloud.ext.mq.config;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.cloud.ext.util.ExtMap;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.utils.SerializationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;


/**
 * 处理provider-> exchange-> queue 这2个阶段的到达情况
 * @author xukk
 * @date 2020/3/9
 */
@Component
@Slf4j
public class MqProducerAckConfiguration implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback{


    private final RabbitTemplate rabbitTemplate;

    @Autowired
    public MqProducerAckConfiguration(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate=rabbitTemplate;
    }

    @PostConstruct
    public void init() {
        //指定 ConfirmCallback
        rabbitTemplate.setConfirmCallback(this);
        //指定 ReturnCallback
        rabbitTemplate.setReturnCallback(this);

    }


    /**
     * 只确认消息是否正确到达 Exchange 中
     * 1. 如果消息没有到exchange,则confirm回调,ack=false
     * 2. 如果消息到达exchange,则confirm回调,ack=true
     * @param correlationData 消息
     * @param ack 确认标识位
     * @param cause 失败原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if(!ack) {
            log.warn("消息未正确到达交换机，详情：{}",cause);
        }
    }

    /**
     * 消息没有正确到达队列时触发回调，如果正确到达队列不执行
     * @param message 消息
     * @param replyCode 应答码
     * @param replyText 描述
     * @param exchange  消息使用的交换器
     * @param routingKey 消息使用的路由键
     */
    @Override
    public void returnedMessage(Message message,int replyCode, String replyText, String exchange, String routingKey) {
       ExtMap extMap= ExtMap.builder().build()
                .put("消息主体",SerializationUtils.deserialize(message.getBody()))
                .put("应答码",replyCode)
                .put("描述",replyText)
                .put("消息使用的交换器 exchange",exchange)
                .put("消息使用的路由键 routing",routingKey);
       log.warn("消息未正确到达队列，详情：{}", JSON.toJSONString(exchange,true));
    }
}
